package com.jerry.lastgomall.product.controller;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("redis")
public class RedisTestController {
    @Autowired
    private StringRedisTemplate template;

//    @Autowired
//    private Redisson redisson;


    @RequestMapping("/test")
    public void test(){
        int ticket = Integer.parseInt(template.opsForValue().get("ticket"));
        if (ticket > 0) {
            int realTicket = ticket - 1;
            template.opsForValue().set("ticket", realTicket + "");
            System.out.println("抢票成功，剩余：" + realTicket + "张票");
        } else {
            System.out.println("出票失败！余票不足");
        }
    }

    @RequestMapping("/testLock")
    public String  testLock(){
        //火车的id，下面就是对该车的票加锁
        String productId = "PID222222";
        //表示线程的UUID
        String clientId = UUID.randomUUID().toString();
        try {
            //加锁 ---> setnx lockKey mylock
            //同时需要设置超时，防止该微服务挂了而锁未释放，超时时间应该大于抢票逻辑的执行时间
            Boolean res = template.opsForValue().setIfAbsent(productId, clientId, 10, TimeUnit.SECONDS);
            if (!res) {
                return "error";
            }
            int ticket = Integer.parseInt(template.opsForValue().get("ticket"));
            if (ticket > 0) {
                int realTicket = ticket - 1;
                template.opsForValue().set("ticket", realTicket + "");
                System.out.println("抢票成功，剩余：" + realTicket + "张票");
            } else {
                System.out.println("出票失败！余票不足");
            }
        } finally {
            //校验是否为原来的线程
            //不过不校验，可能出现下面的情况
            /*
                万一抢票逻辑执行时间大于10秒，在中间执行的时候，锁就因为超时而释放了，
                并发环境下又会有第二个线程加锁，开始抢票
                而此时第一个线程抢票完毕，准备释放锁，但是它释放的已经不是自己的锁了，而是第二个线程加的锁
             */
            if (clientId.equals(template.opsForValue().get(productId))) {
                //释放锁
                template.delete(productId);
            }
        }

        return "end";
    }

//    @RequestMapping("/testRedisson")
//    public void testRedisson(){
//        //火车的id，下面就是对该车的票加锁
//        String productId = "PID222222";
//        RLock redissonLock = redisson.getLock(productId);
//
//        try {
//            redissonLock.lock(30,TimeUnit.SECONDS);
//            int ticket = Integer.parseInt(template.opsForValue().get("ticket"));
//            if (ticket > 0) {
//                int realTicket = ticket - 1;
//                template.opsForValue().set("ticket", realTicket + "");
//                System.out.println("抢票成功，剩余：" + realTicket + "张票");
//            } else {
//                System.out.println("出票失败！余票不足");
//            }
//        }finally {
//            //释放锁
//            redissonLock.unlock();
//        }
//    }
}
